package com.edfeff.bio.adapter;

import com.edfeff.bio.adapter.router.Controller;
import com.edfeff.bio.adapter.router.Req;
import com.edfeff.bio.http.IAdapter;
import com.edfeff.bio.http.Request;
import com.edfeff.bio.http.Response;

import java.lang.reflect.Method;
import java.net.URL;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.List;

public class DynamicRouterAdapter implements IAdapter {
    static String basePackage = "com.edfeff.bio.adapter.router.api";
    static List<MethodRouter> routers = new ArrayList<>();

    @Override
    public void service(Request req, Response res) throws Exception {
        String method = req.getMethod();
        String path = req.getUri();
        for (MethodRouter router : routers) {
            if (router.getReqMethod().equals(method) && router.getPath().equals(path)) {
                invokeRouterMethod(req, res, router);
            }
        }
    }

    private void invokeRouterMethod(Request req, Response res, MethodRouter router) {
        try {
            Class<?> controllerClass = router.getControllerClass();
            Object controller = controllerClass.newInstance();
            Method method = router.getMethod();
            method.invoke(controller, req, res);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    static class MethodRouter {
        private Class<?> controllerClass;
        private Method method;
        private String path;
        private String reqMethod;

        public MethodRouter(Class<?> controllerClass, Method method, String path, String reqMethod) {
            this.controllerClass = controllerClass;
            this.method = method;
            this.path = path;
            this.reqMethod = reqMethod;
        }

        public Class<?> getControllerClass() {
            return controllerClass;
        }

        public Method getMethod() {
            return method;
        }

        public String getPath() {
            return path;
        }

        public String getReqMethod() {
            return reqMethod;
        }
    }

    static {
        try {
            URL location = DynamicRouterAdapter.class.getProtectionDomain().getCodeSource().getLocation();
            Path baseDir = Paths.get(location.toURI());
            Path apiDir = baseDir.resolve(basePackage.replace(".", "/"));
            Files.list(apiDir).forEach(DynamicRouterAdapter::loadControllerClassRouter);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    private static void loadControllerClassRouter(Path f) {
        String fileName = f.getFileName().toString();
        if (fileName.endsWith(".class") && !fileName.contains("$")) {
            String controllerName = fileName.substring(0, fileName.indexOf(".class"));
            try {
                Class<?> controllerClass = Class.forName(basePackage + "." + controllerName);
                Controller annotation = controllerClass.getAnnotation(Controller.class);
                if (annotation == null)
                    return;
                for (Method method : controllerClass.getMethods()) {
                    Req req = method.getAnnotation(Req.class);
                    if (req == null)
                        continue;
                    System.out.printf("Router: %s %s%n", req.method(), req.value());
                    routers.add(new MethodRouter(controllerClass, method, req.value(), req.method()));
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

}
